package com.immediatus.engine.interpolator;


import com.immediatus.engine.contracts.Interpolator;

public class AccelerationInterpolator implements Interpolator{

    private final float _acceleration;
    private final float _deceleration;

    public AccelerationInterpolator(float acceleration_, float deceleration_){
        if (acceleration_ < 0 || acceleration_ > 1){
            throw new IllegalArgumentException(String.format("Acceleration value of %.2f lies outside required [0,1] range.", acceleration_));
        }
        if (deceleration_ < 0 || deceleration_ > 1){
            throw new IllegalArgumentException(String.format("Deceleration value of %.2f lies outside required [0,1] range.", deceleration_));
        }
        double limit = 1.0 - deceleration_;
        if (acceleration_ > limit){
            throw new IllegalArgumentException(String.format("Acceleration value of %.2f is greater than 1 - %.2f (the %s) = %.2f.", acceleration_, deceleration_, "deceleration_", limit));
        }
        limit = 1.0 - acceleration_;
        if (deceleration_ > limit){
            throw new IllegalArgumentException(String.format("Deceleration value of %.2f is greater than 1 - %.2f (the %s) = %.2f.", deceleration_, acceleration_, "acceleration_", limit));
        }
        _acceleration = acceleration_;
        _deceleration = deceleration_;
    }

    @Override
    public float interpolate(float fraction_){
        if (_acceleration != 0 || _deceleration != 0){
            float runRate = 1.0F / (1.0F - _acceleration / 2.0F - _deceleration / 2.0F);
            if (fraction_ < _acceleration){
                float averageRunRate = runRate * (fraction_ / _acceleration) / 2.0F;
                fraction_ *= averageRunRate;
            } else if (fraction_ > (1.0F - _deceleration)){
                float tdec = fraction_ - (1.0F - _deceleration);
                float pdec = tdec / _deceleration;
                fraction_ = runRate * (1.0F - (_acceleration / 2.0F) - _deceleration + tdec * (2.0F - pdec) / 2.0F);
            } else{
                fraction_ = runRate * (fraction_ - (_acceleration / 2.0F));
            }

            if (fraction_ < 0.0F) fraction_ = 0.0F;
            else if (fraction_ > 1.0F) fraction_ = 1.0F;
        }
        return fraction_;
    }
}
